/***************************************************************************
 *   Copyleft 2006-2007 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>			                           *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
 #include "Vector3D.h"

/**************************************************************
* Constructors                                                *
***************************************************************/
Vector3D::Vector3D(const Vector2D vect) {
	mX = vect.mX;
	mY = vect.mY;
	mZ = 0.0f;
}

Vector3D::Vector3D(const Vector3D& vect) {
	mX = vect.mX;
	mY = vect.mY;
	mZ = vect.mZ;
}

/**************************************************************
* Operators                                                   *
***************************************************************/
Vector3D& Vector3D::operator+=(const Vector3D& vectB) {
	mX += vectB.mX;
	mY += vectB.mY;
	mZ += vectB.mZ;

	return *this;
}

Vector3D& Vector3D::operator-=(const Vector3D& vectB) {
	mX -= vectB.mX;
	mY -= vectB.mY;
	mZ -= vectB.mZ;

	return *this;
}

Vector3D Vector3D::operator-() const {
	return Vector3D(-mX, -mY, -mZ);
}

Vector3D& Vector3D::operator*=(const Vector3D& vectB) {
	mX *= vectB.mX;
	mY *= vectB.mY;
	mZ *= vectB.mZ;

	return *this;
}

Vector3D& Vector3D::operator*=(const cFloat fFactor) {
	mX *= fFactor;
	mY *= fFactor;
	mZ *= fFactor;

	return *this;
}
Vector3D& Vector3D::operator=(const Vector3D& vectB) {
	mX = vectB.mX;
	mY = vectB.mY;
	mZ = vectB.mZ;

	return *this;
}

/**************************************************************
* Friend functions                                            *
***************************************************************/
Vector3D operator+(const Vector3D& vectA, const Vector3D& vectB) {
	return Vector3D(vectA.mX + vectB.mX, vectA.mY + vectB.mY, vectA.mZ + vectB.mZ);
}

Vector3D operator-(const Vector3D& vectA, const Vector3D& vectB) {
	return Vector3D(vectA.mX - vectB.mX, vectA.mY - vectB.mY, vectA.mZ - vectB.mZ);
}

Vector3D operator*(const Vector3D& vectA, const Vector3D& vectB) {
	return Vector3D(vectA.mX * vectB.mX, vectA.mY * vectB.mY, vectA.mZ * vectB.mZ);
}

Vector3D operator*(const Vector3D& vectA, const cFloat fFactor) {
	return Vector3D(vectA.mX * fFactor, vectA.mY * fFactor, vectA.mZ * fFactor);
}

/**************************************************************
* Math functions                                              *
***************************************************************/
cVoid Vector3D::Set(cFloat fX, cFloat fY, cFloat fZ) {
	mX = fX;
	mY = fY;
	mZ = fZ;
}

inline cFloat Vector3D::Length() const {
	return sqrtf(Sqr(mX) + Sqr(mY) + Sqr(mZ));
}

inline cFloat Vector3D::SqrLength() const {
	return Sqr(mX) + Sqr(mY) + Sqr(mZ);
}

cVoid Vector3D::Normalize() {
	const cFloat fLength = Length();

	if (fLength == 0) {
		return;
	}
	const cFloat fOneOverLength = 1.0f / fLength;

	mX *= fOneOverLength;
	mY *= fOneOverLength;
	mZ *= fOneOverLength;
}

 cVoid Vector3D::FastNormalize() {
	cFloat fTmp = DotProduct(*this);
	const cFloat fHalf = fTmp + 0.5f;
	cLong lShift = * (cLong*) &fTmp;
	lShift = 0x5f3759df - (lShift >> 1);
	fTmp = * (cFloat*) &lShift;
	const cFloat fLength = fTmp * (1.5f - fHalf * Sqr(fTmp));

	mX *= fLength;
	mY *= fLength;
	mZ *= fLength;
}
cFloat Vector3D::DotProduct(const Vector3D& vectB) {
	return mX * vectB.mX + mY * vectB.mY + mZ * vectB.mZ;
}

cVoid Vector3D::CrossProduct(const Vector3D& vectA, const Vector3D& vectB) {
	mX = vectA.mY * vectB.mZ - vectA.mZ * vectB.mY;
	mY = vectA.mZ * vectB.mX - vectA.mX * vectB.mZ;
	mZ = vectA.mX * vectB.mY - vectA.mY * vectB.mX;
}
